#include "mt03x.h"
#include "rs232.h"
#include "menu.h"
#include "opencv2/opencv.hpp"
#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <sys/prctl.h>
uint32_t cap_temp_value;
uint32_t m_cmd_start = 0;
uint32_t m_cmd_type = 0;

#define APPNAME "IRApp"
static uint8_t s_temp_map[32][32];
std::atomic_flag app_exit = ATOMIC_FLAG_INIT; // always set when checked
void data_handler(void);
int Quit(int argc, char *argv[])
{
    app_exit.clear();
    exit(0);
}

int SetE(int argc, char *argv[])
{
    char buffer[32];
    int value = 0;
    if (argc > 1)
    {
        snprintf(buffer, 31, "%s", argv[1]);
        if (buffer[strlen(buffer) - 1] == '\n')
        {
            buffer[strlen(buffer) - 1] = 0;
        }
        if (IsInt(buffer) == 1)
        {
            value = atoi(buffer);
            if (value > 800 && value < 1200)
            {
                //setBlackLightValue();
                cap_temp_value = value;
                m_cmd_start = 1;
                m_cmd_type = 1;
            }
        }
    }
    return 0;
}

int SetA(int argc, char *argv[])
{
    char buffer[32];
    float value = 0;
    if (argc > 1)
    {
        snprintf(buffer, 31, "%s", argv[1]);
        if (buffer[strlen(buffer) - 1] == '\n')
        {
            buffer[strlen(buffer) - 1] = 0;
        }
        if (IsInt(buffer) == 1)
        {
            value = atof(buffer);
            if (value >= 36 && value <= 37)
            {
                //setBlackLightValue();
                cap_temp_value = (value * 10) + 2731;
                m_cmd_start = 1;
                m_cmd_type = 0;
            }
        }
    }
    return 0;
}
int ReadConfig(int argc, char *argv[])
{
    m_cmd_start = 1;
    m_cmd_type = 2;
    return 0;
}

int main(int argc, char **argv)
{
    sensor_mt03x_init();

    cv::namedWindow(APPNAME, cv::WINDOW_AUTOSIZE);
    app_exit.test_and_set();
    std::thread ext_thread(data_handler);
    ext_thread.detach();

    SetPrompt("MT03X>>");
    MenuConfig("version", "V1.1.0", NULL);
    MenuConfig("quit", "Quit", Quit);
    MenuConfig("SetE", "设置发射率 eg. SetE 975", SetE);
    MenuConfig("SetA", "快速校准 eg. SetA 36.5", SetA);
    MenuConfig("Read", "读取配置 eg. Read", ReadConfig);
    Help(0, NULL);
    ExecuteMenu();
    return 0;
}
void data_handler(void)
{
    volatile int length, tlen, times, comOpen, tempA;
    volatile uint16_t temp = 0, max_temp = 0, min_temp = 0;
    volatile float face_temp = 0.0, set_temp = 0.0, old_face_temp = 0.0;
    u8 *spbuffer = NULL;
    uint8_t buffer[4096];
    prctl(PR_SET_NAME, "Sensor Data Handler");
    com_ext_init();
    comOpen = com_ext_open();
    Delay_ms(1000);
    //printf(">>>>>>>> ext:%s\n", S_EXT_INDEX);
    if (is_file_exist(S_EXT_INDEX) == 1)
    {
        if (comOpen != 0)
        {
            comOpen = com_ext_open();
        }
        if (comOpen == 0)
        {
            printf("=== MT03X INIT ===\n");
            spbuffer = sensor_mt03x_start((uint32_t *)&length);
            if (spbuffer != NULL && length > 0)
            {
                if (com_ext_send(spbuffer, length) != 0)
                {
                    Delay_ms(1000);
                    com_ext_send(spbuffer, length);
                }
            }
            length = com_ext_read(buffer, 4095);
            times = 0;
            while (length < (37))
            {
                Delay_ms(10);
                tlen = com_ext_read(buffer + length, 4095);
                if (tlen > 0)
                {
                    //printf("|CC> Ext len ++ %u\n", tlen);
                    length = tlen + length;
                    buffer[length] = 0;
                }
                if ((++times) > 30)
                {
                    printf("|CC> Ext read timeout %u\n", length);
                    break;
                }
            }
            if (length >= 37)
            {
                sensor_mt03x_init_config(buffer, length);
            }
            else
            {
                printf("=== MT03X REINIT ===\n");
                spbuffer = sensor_mt03x_start((uint32_t *)&length);
                if (spbuffer != NULL && length > 0)
                {
                    if (com_ext_send(spbuffer, length) != 0)
                    {
                        Delay_ms(1000);
                        com_ext_send(spbuffer, length);
                    }
                }
                length = com_ext_read(buffer, 4095);
                times = 0;
                while (length < (37))
                {
                    Delay_ms(10);
                    tlen = com_ext_read(buffer + length, 4095);
                    if (tlen > 0)
                    {
                        //printf("|CC> Ext len ++ %u\n", tlen);
                        length = tlen + length;
                        buffer[length] = 0;
                    }
                    if ((++times) > 30)
                    {
                        printf("|CC> Ext read timeout %u\n", length);
                        break;
                    }
                }
                if (length >= 37)
                {
                    sensor_mt03x_init_config(buffer, length);
                }
            }
            //app_ui_temp_hotmap_pos_flush();
        }
    }
    printf("配置信息读取成功\n");

    while (app_exit.test_and_set())
    {
        if (comOpen != 0)
        {
            comOpen = com_ext_open();
            Delay_ms(100);
        }
        if (comOpen == 0)
        {
            tempA = 0;
            if (m_cmd_start == 0)
            {
                tempA = 1;
                spbuffer = sensor_mt03x_get_query((uint32_t *)&length);
                if (spbuffer != NULL && length > 0)
                {
                    if (com_ext_send(spbuffer, length) < 0)
                    {
                        Delay_ms(500);
                        while (is_file_exist(S_EXT_INDEX) != 1)
                        {
                            Delay_ms(2000);
                        }
                        comOpen = -1;
                        continue;
                    }
                }
            }
            else
            {
                tempA = 2;
                Delay_ms(600);
                memset(buffer, 0, 4096);
                length = com_ext_read(buffer, 4095);
                Delay_ms(200);
                memset(buffer, 0, 4096);
                length = com_ext_read(buffer, 4095);

                if (m_cmd_type == 0)
                {
                    spbuffer = sensor_mt03x_get_setA((uint32_t *)&length, cap_temp_value);
                }
                else if (m_cmd_type == 1)
                {
                    spbuffer = sensor_mt03x_get_setE((uint32_t *)&length, cap_temp_value);
                }
                else if (m_cmd_type == 2)
                {
                    spbuffer = sensor_mt03x_start((uint32_t *)&length);
                }

                if (spbuffer != NULL && length > 0)
                {
                    if (com_ext_send(spbuffer, length) < 0)
                    {
                        Delay_ms(500);
                        while (is_file_exist(S_EXT_INDEX) != 1)
                        {
                            Delay_ms(2000);
                        }
                        comOpen = -1;
                        m_cmd_start = 0;
                        continue;
                    }
                }
            }
        }
        else
        {
            printf("|CC> Ext open error\n");

            Delay_ms(1000);
            while (is_file_exist(S_EXT_INDEX) != 1)
            {
                Delay_ms(2000);
            }
            continue;
        }
        memset(buffer, 0, 4096);
        length = com_ext_read(buffer, 4095);
        times = 0;
        if (m_cmd_start == 0)
        {
            while (length < (sensor_mt03x_get_minisize()))
            {
                Delay_ms(5);
                tlen = com_ext_read(buffer + length, 4095);
                if (tlen > 0)
                {
                    //printf("|CC> Ext len ++ %u\n", tlen);
                    length = tlen + length;
                    buffer[length] = 0;
                }
                if ((++times) > 50)
                {
                    printf("|CC> Ext read timeout %u\n", length);
                    break;
                }
            }
            if (length >= sensor_mt03x_get_minisize() && length < 4096)
            {
                sensor_mt03x_common_handler(buffer, length);
            }
            else
            {
                printf("|CC> Ext read len error %u\n", length);
            }
        }
        else
        {
            while (length < (7))
            {
                //ui_mutex.lock();
                //app_debug_printf(_("Calibration:Wait.\n"));
                printf("Calibration:Wait.\n");
                //ui_mutex.unlock();
                Delay_ms(1000);

                tlen = com_ext_read(buffer + length, 4095);
                if (tlen > 0)
                {
                    //printf("|CC> Ext len ++ %u\n", tlen);
                    length = tlen + length;
                    buffer[length] = 0;
                }
                if ((++times) > 15)
                {
                    printf("|CC> Ext read timeout %u\n", length);
                    break;
                }
            }
            printf("Calibration Recv %u\n", length);
            //ui_mutex.lock();
            if (length >= 8 && length < 4096)
            {
                if (buffer[7] == 0x25)
                {
                    //app_debug_printf(_("Calibration:OK\n"));
                    printf("Calibration:OK\n");
                }
                else
                {
                    //app_debug_printf(_("Calibration:Fail\n"));
                    printf("Calibration:Fail\n");
                }
            }
            else
            {
                printf("|CC> Ext read len error %u\n", length);
                //pp_debug_printf(_("Calibration:Error\n"));
            }
            //ui_mutex.unlock();
            m_cmd_start = 0;
            Delay_ms(100);
            spbuffer = sensor_mt03x_start((uint32_t *)&length);
            if (spbuffer != NULL && length > 0)
            {
                if (com_ext_send(spbuffer, length) != 0)
                {
                    Delay_ms(1000);
                    com_ext_send(spbuffer, length);
                }
            }
            length = com_ext_read(buffer, 4095);
            times = 0;
            while (length < (37))
            {
                Delay_ms(10);
                tlen = com_ext_read(buffer + length, 4095);
                if (tlen > 0)
                {
                    //printf("|CC> Ext len ++ %u\n", tlen);
                    length = tlen + length;
                    buffer[length] = 0;
                }
                if ((++times) > 30)
                {
                    printf("|CC> Ext read timeout %u\n", length);
                    break;
                }
            }
            if (length >= 37)
            {
                sensor_mt03x_init_config(buffer, length);
            }
        }
    }
}

void app_callback_flush_new_thermal_img(uint16_t *mtemp_buffer, uint32_t width, uint32_t height, float atemp, float ta)
{
    char buf[16];
    cv::Mat thermal(height, width, CV_8UC1);
    uchar *ptmp = NULL;
    volatile uint16_t temp = 0, max_temp = 0, min_temp = 0xFFFF;
    for (int i = 0; i < (width * height); ++i)
    {
        if (mtemp_buffer[i] >= 2731 && mtemp_buffer[i] < 3731)
        {
            temp = mtemp_buffer[i] - 2731;
            if (max_temp < temp)
            {
                max_temp = temp;
            }
            if (min_temp > temp)
            {
                min_temp = temp;
            }
        }
        else
        {
            printf("-- %u\n", mtemp_buffer[i]);
        }
    }
    //m_ta = ta;
    //m_avg = atemp;

    if (max_temp > min_temp)
    {
        uint16_t diff = max_temp - min_temp;
        float step = 255.0 / diff;
        if (width == 4 && height == 4)
        {
            step = (float)(235.0 / diff);
        }
        for (int i = 0; i < (width * height); ++i)
        {
            temp = mtemp_buffer[i];
            if (temp >= 2731)
            {
                if (temp < 3731)
                {
                    temp = (temp - 2731);
                    float c = step * (temp - min_temp);
                    s_temp_map[i / width][i % width] = (uint8_t)c;
                }
                else
                {
                    s_temp_map[i / width][i % width] = 0xFF;
                }
            }
            else
            {
                s_temp_map[i / width][i % width] = 0;
            }
        }

        for (int i = 0; i < height; ++i)
        {
            ptmp = thermal.ptr<uchar>(i);

            for (int j = 0; j < width; ++j)
            {
                ptmp[j] = s_temp_map[i][j];
            }
        }

        {
            cv::Mat vsframe;
            vsframe = cv::Mat(cv::Size(280, 280), CV_8UC3);
            if (width == 4 && height == 4)
            {
                cv::Mat img_header;
                cv::applyColorMap(thermal, img_header, cv::COLORMAP_JET);
                //transpose(thermal, thermal);
                //flip(thermal, thermal, 0);

                int wsize = 280 / 4;
                int hsize = 280 / 4;
                for (int i = 0; i < height; ++i)
                {
                    for (int j = 0; j < width; ++j)
                    {
                        if (((j * wsize + wsize - 1) < 280) &&
                            ((i * hsize + hsize - 1) < 280) &&
                            ((j * wsize) >= 0) &&
                            ((i * hsize) >= 0))
                        {
                            cv::Point A = cv::Point(j * wsize, i * hsize);
                            cv::Point B = cv::Point(j * wsize + wsize - 1, i * hsize + hsize - 1);
                            cv::Scalar rgb = cv::Scalar(img_header.at<cv::Vec3b>(i, j)[0], img_header.at<cv::Vec3b>(i, j)[1], img_header.at<cv::Vec3b>(i, j)[2]);
                            cv::rectangle(vsframe, A, B, rgb, cv::LineTypes::FILLED);
                        }
                        else
                        {
                            printf("Rectangle Error %u,%u - %u,%u", i, j, (j * wsize + wsize - 1), (i * hsize + hsize - 1));
                        }
                    }
                }
            }
            else
            {
                cv::Mat img_header;
                cv::applyColorMap(thermal, img_header, cv::COLORMAP_JET);
                cv::resize(img_header, vsframe, vsframe.size());
            }
            snprintf(buf, 15, "%05.2f", atemp);
            int font_face = cv::FONT_HERSHEY_COMPLEX;
            double font_scale = 1;
            int thickness = 1;
            int baseline;
            //获取文本框的长宽
            cv::Size text_size = cv::getTextSize(buf, font_face, font_scale, thickness, &baseline);
            cv::Point origin;
            origin.x = 10;
            origin.y = 50;
            cv::putText(vsframe, buf, origin, font_face, font_scale, cv::Scalar(255, 255, 255), thickness, 2, 0);
            //printf("%02.5f~%02.5f\n", max_temp / 10.0, min_temp / 10.0);
            cv::imshow(APPNAME, vsframe);
            cv::waitKey(33);
            //vsframe.copyTo(irUiFrame);
        }
    }
}
